<?php

namespace app\admin\model\payment;

use addons\payment\library\behavior\OrderInterface;
use app\common\library\Auth;
use think\Hook;
use think\Model;
use traits\model\SoftDelete;

class Order extends Model
{
    use SoftDelete;
    // 表名
    protected $name = 'payment_order';
    
    // 自动写入时间戳字段
    protected $autoWriteTimestamp = 'int';

    // 定义时间戳字段名
    protected $createTime = 'createtime';
    protected $updateTime = 'updatetime';
    protected $deleteTime = 'deletetime';

    // 追加属性
    protected $append = [
        'status_text',
        'paytime_text'
    ];
    
    public function channel() {
        return $this->belongsTo(Channel::class, 'payment_channel_id');
    }

    public function getStatusList()
    {
        return ['wait' => __('Status wait'), 'pay' => __('Status pay'), 'cancel' => __('Status cancel'), 'refund' => __('Status refund')];
    }

    public function getStatusTextAttr($value, $data)
    {
        $value = $value ? $value : (isset($data['status']) ? $data['status'] : '');
        $list = $this->getStatusList();
        return isset($list[$value]) ? $list[$value] : '';
    }

    public function getPaytimeTextAttr($value, $data)
    {
        $value = $value ? $value : (isset($data['paytime']) ? $data['paytime'] : '');
        return is_numeric($value) ? date("Y-m-d H:i:s", $value) : $value;
    }

    protected function setHookClassAttr($value) {
        if (is_array($value)) {
            return implode(",", $value);
        }
        return $value;
    }

    protected function getHookClassAttr($value) {
        return empty($value) ? [] : explode(',', $value);
    }

    protected function setPaytimeAttr($value)
    {
        return $value === '' ? null : ($value && !is_numeric($value) ? strtotime($value) : $value);
    }

    /**
     * 创建订单
     *
     * @param string $title 支付标题
     * @param float $price 支付金额
     * @param string $payType 支付方式
     * @param string $hookName 触发行为名称
     * @param string|array $hookClass 监听行为类
     * @param array $hookData 行为额外数据
     * @param Channel $channel 支付渠道
     * @param array $moreData 覆盖数据
     * @return self
     */
    public static function createOrder($title, $price, $payType, $hookName, $hookClass, $hookData = [], Channel $channel = null, $moreData = []) {
        $order = new self(
            array_merge([
                'order_number' => Order::makeOrderNumber(),
                'user_id' => Auth::instance()->isLogin() ? Auth::instance()->id : 0, // 下单用户
                'user_type' => 'user', // 用户模型 多态关联
                'model_id' => 0, // 模型id
                'model_type' => '', // 模型名称 多态关联
                'payment_channel_id' => $channel ? $channel->id : 0, // 支付渠道id
                'title' => $title, //支付标题,
                'price' => $price, // 支付金额,
                'pay_type' => $payType, // 支付类型调用对应支付类型
                'out_order_number' => '', //选填
                'pay_data' => '', // 支付数据 重复使用 比如app的支付参数
                'pay_param' => '', // 支付回调参数 回调时使用
                'hook_name' => $hookName, // 行为名称
                'hook_class' => is_array($hookClass) ?  $hookClass : explode(",", $hookClass), // 行为监听类 用,隔开
                'hook_data' => $hookData, // 行为下传数据 可选
            ], $moreData)
        );
        $order->save();
        return $order;
    }

    public static function makeOrderNumber() {
        $int = '';
        $len = 16;
        while (strlen($int) != $len) {
            $int .= mt_rand(0, 9);
        }

        return date('Ymd').substr(implode('', array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 8) . $int;
    }

    /**
     * 检测订单的监听类是否正常
     *
     * @return boolean
     */
    public function checkHookClass() {
        foreach($this->hook_class as $hc) {
            if (!class_exists($hc) ) {
                $this->error = $hc . ' 监听类未找到';
                return false;
            }
            $tmpClass = new $hc;
            if (!$tmpClass instanceof OrderInterface) {
                $this->error = $hc . '监听类必须实现' . OrderInterface::class;
                return false;
            }
        }
        return true;
    }

    /**
     * 判断当前订单是否能支付
     *
     * @return boolean
     */
    public function canPay() {
        if ($this->status != 'wait') {
            $this->error = '订单状态不是等待支付';
            return false;
        }
        return true;
    }
    
    /**
     * 支付订单
     *
     * @param string $status 状态
     * @param float $price 支付金额
     * @param array $params 额外属性
     * @return bool
     */
    public function pay($status, $price = 0, $params = []) {
        if ( !$this->canPay() ) {
            return false;
        }
        $data = array_merge([
            'status' => $status,
            'pay_price' => $price
        ], $params);
        $this->allowField(true)->save($data);
        $this->doHook();
        return true;
    }

    /**
     * 触发一次行为
     *
     * @return bool
     */
    public function doHook() {
        if (empty($this->hook_name)) {
            $this->error = '行为名为空';
            return false;
        }
        if ($this->hook_status == 'success') {
            $this->error = '行为状态已执行,不可重复执行';
            return false;
        }
        $allHookTag = Hook::get($this->hook_name);
        foreach($this->hook_class as $hc) {
            if (empty($hc)) {
                continue;
            }
            if (!in_array($hc, $allHookTag)) {
                Hook::add($this->hook_name, $hc);
            }
        }

        try {
            Hook::listen($this->hook_name, $this);
            $this->hook_status = 'success';
        } catch (\Exception $e) {
            $this->hook_status = 'error';
            $this->hook_data = $e->getTraceAsString();
        }
        $this->save();
        return true;
    }
}
